package core

import (
	"net"
	"sync"
)

type TopicFromDB struct {
	ID      uint64               // 主题ID
	Name    string               // 主题名称,支持节点，如test/topic
	Qos     uint8                // QoS等级,如果推送的消息内不含QoS，则以此值为准
	Type    uint8                //主题类型，0为默认值，为所有成员发送，1为仅选择1个成员发送，方便做负载均衡
	Clients map[net.Conn]*Client // 订阅该主题的客户端
}

func NewTopicInfo(id uint64, name string, qos uint8) *TopicFromDB {
	return &TopicFromDB{
		ID:      id,
		Name:    name,
		Qos:     qos,
		Clients: make(map[net.Conn]*Client),
	}
}
func (t *TopicFromDB) AddClient(conn net.Conn, client *Client) {
	t.Clients[conn] = client
}
func (t *TopicFromDB) RemoveClient(conn net.Conn) {
	delete(t.Clients, conn)
}

// ///////////////////////////////////////////////////////////////////////
var (
	instance_topic *TopicManager
	once_topic     sync.Once
)

// TopicManager 用于管理所有主题
type TopicManager struct {
	Topics map[string]*TopicFromDB // 主题名称到TopicInfo的映射
}

func NewTopicManager() *TopicManager {
	return &TopicManager{
		Topics: make(map[string]*TopicFromDB),
	}
}
func GetTopicMng() *TopicManager {
	once_topic.Do(func() {
		instance_topic = NewTopicManager()
	})
	return instance_topic
}

// 主题管理，只能加载，不能在程序内部创建，方便统一管理
func (tm *TopicManager) LoadAllTopicsInfoFromDB() {
	GetDBCmd().ReadAllTopicsInfoFromDB(tm)
}

func (tm *TopicManager) SelectTopic(topic string) *TopicFromDB {
	if obj, exist := tm.Topics[topic]; exist {
		return obj
	} else {
		GetLog().WriteLog(Log_Debug, "load topic from db,name:"+topic)
		return GetDBCmd().ReadOneTopic(tm, topic)
	}
}
func (tm *TopicManager) UnRegisterSubsMsg(client *Client, sub *Subscriber) *SubscriberAck {
	ack := NewSubscriberAck()
	ack.ClientID = client.ClientID
	for topic := range sub.TopicsQos {
		t := NewTopicAck()
		t.Name = topic
		if tp := tm.SelectTopic(topic); tp != nil {
			tp.RemoveClient(client.Conn)
			t.Result = true
			t.Error = "nil"
			t.Qos = tp.Qos
			t.Command = false
		} else {
			t.Qos = MQ_QOS_0
			t.Command = false
			t.Result = false
			t.Error = "topic not exist"
		}
		ack.Topics[topic] = t
	}
	return ack
}
func (tm *TopicManager) RegisterSubsMsg(client *Client, sub *Subscriber) *SubscriberAck {
	ack := NewSubscriberAck()
	ack.ClientID = client.ClientID
	for topic := range sub.TopicsQos {
		t := NewTopicAck()
		t.Name = topic
		if tp := tm.SelectTopic(topic); tp != nil {
			tp.AddClient(client.Conn, client)
			t.Result = true
			t.Error = "nil"
			t.Qos = tp.Qos
			t.Command = true
		} else {
			t.Qos = MQ_QOS_0
			t.Command = true
			t.Result = false
			t.Error = "topic not exist"
		}
		ack.Topics[topic] = t
	}
	return ack
}
